namespace DCHealthCheck.DomainModel {

    #region Usings
    using DCHealthCheck.Common;
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Diagnostics;
    using System.Text;
    
    #endregion

    [Table("ServiceInfo")]
    public class ServiceInfo : IServiceInfo, IObjectWithState, IValidatableObject {

        #region Members
        #region Max length fields
        public static readonly int DisplayNameMaxLength = 255;
        public static readonly int NameMaxLength = 255;
        public static readonly int PathNameMaxLength = 255;
        public static readonly int StartNameMaxLength = 255;
        #endregion

        public static readonly string CSVHeader =
            "DCName,Domain,ADSite,OSVersion,HealthCheckDate," +
            "ProcessId,DisplayName,Name,PathName,ErrorControl,ExitCode,ServiceType,Started,StartMode,StartName,State,Status";

        public virtual string DisplayName { get; set; }

        public virtual ServiceErrorControl ErrorControl { get; set; }

        public virtual WINERROR ExitCode { get; set; }

        public virtual long Id { get; set; }

        public virtual string Name { get; set; }

        public virtual string PathName { get; set; }

        public virtual long ProcessId { get; set; }

        public virtual ServiceType ServiceType { get; set; }

        public virtual bool Started { get; set; }

        public virtual ServiceStartMode StartMode { get; set; }

        public virtual string StartName { get; set; }

        public virtual ServiceState State { get; set; }

        public virtual ServiceStatus Status { get; set; }

        #region Related Entities
        public virtual SystemInfo SystemInfo {
            get { return systemInfo; }
            set {
                systemInfo = value;
                if (systemInfo != null) {
                    if (this.SystemInfoId != systemInfo.Id) {
                        this.SystemInfoId = systemInfo.Id;
                    }
                }
            }
        }
        private SystemInfo systemInfo;

        [ForeignKey("SystemInfo")]
        public virtual Guid SystemInfoId {
            get {
                if (this.SystemInfo != null) return this.SystemInfo.Id;
                return systemInfoId;
            }
            set { systemInfoId = value; }
        }
        private Guid systemInfoId;
        #endregion

        #region NotMapped properties
        [NotMapped]
        public string DCSamAccountNameFriendly {
            get {
                if ((this.SystemInfo != null) && (this.SystemInfo.DomainController != null) && (this.SystemInfo.DomainController.SamAccountNameFriendly != null)) {
                    return this.SystemInfo.DomainController.SamAccountNameFriendly;
                }
                else {
                    return string.Empty;
                }
            }
        }

        [NotMapped]
        public DetachedState DetachedState { get; set; }

        [NotMapped]
        public Object EntityKey { get { return this.Id; } }

        [NotMapped]
        public Dictionary<string, object> StartingOriginalValues { get; set; }
        #endregion 
        #endregion

        #region Constructor
        public ServiceInfo() {
            this.DetachedState = DCHealthCheck.DomainModel.DetachedState.Unchanged;

            this.DisplayName = string.Empty;
            this.Name = string.Empty;
            this.PathName = string.Empty;
            this.ProcessId = -1;
            this.StartName = string.Empty;
        } 
        #endregion

        #region Methods
        public string ToCSVString() {
            var info = new StringBuilder();

            #region DC Info
            info.AppendFormat("\"{0}\",", this.SystemInfo.DomainController.SamAccountNameFriendly);
            info.AppendFormat("\"{0}\",", this.SystemInfo.DomainController.NetbiosDomain);
            info.AppendFormat("\"{0}\",", this.SystemInfo.DomainController.ADSite);
            info.AppendFormat("\"{0}\",", this.SystemInfo.DomainController.OSVersion);
            #endregion
            info.AppendFormat("\"{0}\",", this.SystemInfo.CheckDateTimeUTC.ToString("yyyy-MM-dd HH:mm"));

            info.AppendFormat("\"{0}\",", this.ProcessId);
            info.AppendFormat("\"{0}\",", this.DisplayName);
            info.AppendFormat("\"{0}\",", this.Name);
            info.AppendFormat("\"{0}\",", this.PathName);
            info.AppendFormat("\"{0}\",", this.ErrorControl);
            info.AppendFormat("\"{0}\",", this.ExitCode);
            info.AppendFormat("\"{0}\",", this.ServiceType);
            info.AppendFormat("\"{0}\",", this.Started);
            info.AppendFormat("\"{0}\",", this.StartMode);
            info.AppendFormat("\"{0}\",", this.StartName);
            info.AppendFormat("\"{0}\",", this.State);
            info.AppendFormat("\"{0}\",", this.Status);

            return info.ToString();
        }

        [DebuggerStepThroughAttribute]
        public override string ToString() {
            var info = new StringBuilder();

            info.Append("ServiceInfo: ");

            if ((this.SystemInfo != null) && (this.SystemInfo.DomainController != null) && (this.SystemInfo.DomainController.DNSName != null)) {
                info.AppendFormat("DC: {0}; ", this.SystemInfo.DomainController.DNSName);
            }
            if (this.SystemInfo != null) {
                info.AppendFormat("HealthCheck Date: {0}; ", this.SystemInfo.CheckDateTimeUTC.ToString("yyyy-MMM-dd"));
            }
            info.AppendFormat("Service: {0}", (this.DisplayName != null) ? this.DisplayName : "NULL");

            return info.ToString();
        }

        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {
            if ((this.DetachedState != DCHealthCheck.DomainModel.DetachedState.Added) && (this.Id < 1)) {
                yield return new ValidationResult(
                    "Id is required.", new[] { "Id" });
            }

            if (this.DetachedState != DCHealthCheck.DomainModel.DetachedState.Deleted) {
                // add entity to SystemInfo, let DetectChanges perform relationship fixup
                if (this.SystemInfoId == Guid.Empty) {
                    yield return new ValidationResult(
                        "SystemInfoId is required.", new[] { "SystemInfoId" });
                }

                if ((this.SystemInfo != null) && (this.SystemInfo.Id != this.SystemInfoId)) {
                    yield return new ValidationResult(
                        "SystemInfo.Id does not match SystemInfoId.", new[] { "SystemInfo, SystemInfoId" });
                }

                if (string.IsNullOrWhiteSpace(this.DisplayName)) {
                    yield return new ValidationResult(
                        "DisplayName is required.", new[] { "DisplayName" });
                }
                else if (this.DisplayName.Length > DisplayNameMaxLength) {
                    yield return new ValidationResult(string.Format("DisplayName length: {0} exceeds max length: {1}",
                        this.DisplayName.Length, DisplayNameMaxLength), new[] { "DisplayName" });
                }

                if (this.ErrorControl == ServiceErrorControl.NotSpecified) {
                    yield return new ValidationResult("ErrorControl is required.", new[] { "ErrorControl" });
                }

                if (string.IsNullOrWhiteSpace(this.Name)) {
                    yield return new ValidationResult(
                        "Name is required.", new[] { "Name" });
                }
                else if (this.Name.Length > NameMaxLength) {
                    yield return new ValidationResult(string.Format("Name length: {0} exceeds max length: {1}",
                        this.Name.Length, NameMaxLength), new[] { "Name" });
                }

                if (string.IsNullOrWhiteSpace(this.PathName)) {
                    yield return new ValidationResult(
                        "PathName is required.", new[] { "PathName" });
                }
                else if (this.PathName.Length > PathNameMaxLength) {
                    yield return new ValidationResult(string.Format("PathName length: {0} exceeds max length: {1}",
                        this.PathName.Length, PathNameMaxLength), new[] { "PathName" });
                }

                if (this.ProcessId < 0) {
                    yield return new ValidationResult(
                        "ProcessId is required.", new[] { "ProcessId" });
                }

                if (this.ServiceType == ServiceType.NotSpecified) {
                    yield return new ValidationResult(
                        "ServiceType is required.", new[] { "ServiceType" });
                }

                if (this.StartMode == ServiceStartMode.NotSpecified) {
                    yield return new ValidationResult(
                        "StartMode is required.", new[] { "StartMode" });
                }

                if (string.IsNullOrWhiteSpace(this.StartName)) {
                    yield return new ValidationResult(
                        "StartName is required.", new[] { "StartName" });
                }
                else if (this.StartName.Length > StartNameMaxLength) {
                    yield return new ValidationResult(string.Format("StartName length: {0} exceeds max length: {1}",
                        this.StartName.Length, StartNameMaxLength), new[] { "StartName" });
                }

                if (this.State == ServiceState.NotSpecified) {
                    yield return new ValidationResult(
                        "State is required.", new[] { "State" });
                }

                if (this.Status == ServiceStatus.NotSpecified) {
                    yield return new ValidationResult(
                        "Status is required.", new[] { "Status" });
                }
            } // if (this.DetachedState != State.Deleted)
        }
        
        #endregion
    }
}
